var _C = document.getElementById("C");
const ctx = _C.getContext('2d');

// 配置
var beginPoint = { x: 50, y: 50 };
var gridSize = 50;
var stoneSize = 20;
var boardSize = 6;
const BLACK = 1;
const WHITE = 2;
// var colorTable={}

// 全局变量
var nums = [0, 18, 18];
var cursorPos = { x: 0, y: 0 }
var turn = 1; // 1 黑 or 2 白
var stage = 1; // 行棋步骤分为 1 布局、 2 开局和 3 行子三个阶段。 
var first = 0; // 先成方者 
var curStone = null; // 被选中的棋子
var moveCount = 0;
var stones = new Array(boardSize * boardSize)
var stoneFangMap = {}
// [sg] ; sg::={ color: color, stones: Map, qis: Map} ; Map::=[int:{x,y}]
var stoneGroups = new Array();

// 各种函数
function boardFull() {
    return nums[BLACK] === 0 && nums[WHITE] === 0;
}
function flipColor(c) {
    return 3 - c;
}
var toI = function (i, j) {
    return i * boardSize + j
}
var sget = function (i, j) {
    return stones[i * boardSize + j]
}
var sset = function (i, j, color) {
    stones[i * boardSize + j] = color
}

// 加入到已有棋块
var sgadd = function (x, y, color) {
    if (stoneGroups.length == 0) {
        var e = {
            color: color,
            stones: new Map([[toI(x, y), { x: x, y: y }]]),
            qis: slmergePoss(new Map(), findNeighbors(x, y))
        }
        stoneGroups.push(e)
    } else {
        // 寻找四个气，如同色，则寻找自己所在的区块
        // 最终找到所有的棋子块 stone group
        var myGroups = findGroupsColor(x, y, color)
        // console.log("myGroups", myGroups)
        sgmerge(x, y, color, myGroups, findNeighborsColor(x, y, 0))
        // 这里不如把所有的气重新算一遍？？？
        // sgRemoveAllQiSelf(x, y)
    }
}
// 根据位置查找棋子块
// return index
var sgget = function (x, y) {
    for (var i = 0; i < stoneGroups.length; i++) {
        var sgs = stoneGroups[i].stones
        if (sgs.has(toI(x, y))) return i
    }
    return -1
}
var sgRemoveItems = function (indexs) {
    var newsgs = []
    for (var i = 0; i < stoneGroups.length; i++) {
        if (indexs.indexOf(i) == -1) {
            newsgs.push(stoneGroups[i])
        }
    }
    return newsgs
}
// indexes: 块索引
var sgmerge = function (x, y, color, indexs, qis) {
    var ss = new Map()
    var newQi = new Map()
    for (let idx of indexs) {
        ss = slmerge(ss, stoneGroups[idx].stones)
        // newQi = slmerge(newQi, stoneGroups[idx].qis)
    }
    ss.set(toI(x, y), { x: x, y: y })

    // now ss all together
    var newsgs = sgRemoveItems(indexs)
    newsgs.push({ color: color, stones: ss, qis: newQi })
    stoneGroups = newsgs

    // 差分的更新气
    var gs = findGroups(x, y)
    for (let i of gs) {
        stoneGroups[i] = sgUpdateQi(stoneGroups[i])
    }
    var i = sgget(x, y)
    stoneGroups[i] = sgUpdateQi(stoneGroups[i])
}

var slmerge = function (a, b) {
    var ret = new Map();
    for (let entry of a) {
        ret.set(entry[0], entry[1])
    }
    for (let entry of b) {
        ret.set(entry[0], entry[1])
    }
    return ret
}
var slmergePoss = function (a, b) {
    var ret = new Map();
    for (let entry of a) {
        ret.set(entry[0], entry[1])
    }
    for (let entry of b) {
        ret.set(toI(entry.x, entry.y), entry)
    }
    return ret
}
var sgRemoveAllQiSelf = function (x, y) {
    for (var i = 0; i < stoneGroups.length; i++) {
        stoneGroups[i].qis.delete(toI(x, y))
    }
}
var boardClear = function () {
    for (var i = 0; i < boardSize; i++) {
        for (var j = 0; j < boardSize; j++) {
            sset(i, j, 0)
        }
    }
    stoneGroups = [];
}
// 找到邻居 可能4 3 2 个
var findNeighbors = function (x, y) {
    var ret = [];
    if (x - 1 >= 0) {
        ret.push({ x: x - 1, y: y })
    }
    if (x + 1 < boardSize) {
        ret.push({ x: x + 1, y: y })
    }
    if (y - 1 >= 0) {
        ret.push({ x: x, y: y - 1 })
    }
    if (y + 1 < boardSize) {
        ret.push({ x: x, y: y + 1 })
    }
    return ret;
}
// 找到同色的邻居
var findNeighborsColor = function (x, y, color) {
    return findNeighbors(x, y).filter((v, i) => sget(v.x, v.y) == color)
}
var findGroups = function (x, y) {
    var poss = findNeighbors(x, y)
    var ret = [];
    for (let pos of poss) {
        var i = sgget(pos.x, pos.y);
        if (i == -1) continue;
        if (ret.indexOf(i) == -1) {
            ret.push(i)
        }
    }
    return ret
}
var findGroupsColor = function (x, y, color) {
    var poss = findNeighborsColor(x, y, color)
    var ret = [];
    for (let pos of poss) {
        if (sget(pos.x, pos.y) == color) {
            var i = sgget(pos.x, pos.y);
            if (ret.indexOf(i) == -1) {
                ret.push(i)
            }
        }
    }
    return ret
}
var removeStonesOnBoard = function (stones) {
    for (let pos of stones) {
        sset(pos.x, pos.y, 0)
    }
}
var sgUpdateQi = function (sg) {
    var stones = sg.stones
    sg.qis = new Map()
    for (let s of stones.values()) {
        var n = findNeighborsColor(s.x, s.y, 0)
        if (n.length > 0) {
            for (let pos of n) {
                sg.qis.set(toI(pos.x, pos.y), pos)
            }
        }
    }
    return sg
}
var sgUpdateAllQi = function () {
    for (let sg of stoneGroups) {
        sgUpdateQi(sg)
    }
}
// 下一步棋 位置 颜色
var makeMove = function (cursorPos, turn) {
    // 落子
    sset(cursorPos.x, cursorPos.y, turn)
}
// for test
function makeFullBoard() {
    for (var i = 0; i < boardSize; i++) {
        for (var j = 0; j < boardSize; j++) {
            var color = parseInt(Math.random() * 2) + 1;
            nums[color]--
            if (nums[color] < 0) {
                color = 3 - color;
                nums[color]--
            }
            sset(i, j, color)
        }
    }
    // console.log(countFang())
    calculateTizi()
    stage = 2
}

function isFang(x, y) {
    var c = isZhiFang(x, y);
    if (c === 0) {
        return isXieFang(x, y);
    }
    return c
}
function isFangOrLong(x, y) {
    var c = isZhiFang(x, y);
    if (c === 0) {
        c = isXieFang(x, y);
        if (c === 0) {
            console.log("will check isLong")
            return isLong(x, y);
        }
    }
    return c
}
function isLong(x, y) {
    var positions = []
    for (var j = 0; j < boardSize; j++) {
        positions.push({ x: x, y: j })
    }
    // console.log(positions)
    var color = isAllColorSame(positions)
    if (color !== 0) {
        return color;
    }
    var positions = []
    for (var i = 0; i < boardSize; i++) {
        positions.push({ x: i, y: y })
    }
    var color = isAllColorSame(positions)
    if (color !== 0) {
        return color;
    }
    return 0;
}
function allPosIn(a) {
    for (let pos of a) {
        if (!(pos.x >= 0 && pos.y >= 0 && pos.x < boardSize && pos.y < boardSize)) {
            return false
        }
    }
    return true
}
function getZhiFang(i, j, k) {
    var ret = []
    var a = [
        { x: i, y: j },
        { x: i + k, y: j + k },
        { x: i + k, y: j },
        { x: i, y: j + k }
    ]
    if (allPosIn(a)) {
        ret.push(a)
    }
    a = [
        { x: i, y: j },
        { x: i - k, y: j + k },
        { x: i - k, y: j },
        { x: i, y: j + k }
    ]
    if (allPosIn(a)) {
        ret.push(a)
    }
    return ret
}
function isZhiFang(i, j) {
    var a = getZhiFang(i, j, 1)
    for (let poss of a) {
        var color = isAllColorSame(poss)
        if (color !== 0) {
            return color
        }
    }
    var a = getZhiFang(i, j, -1)
    for (let poss of a) {
        var color = isAllColorSame(poss)
        if (color !== 0) {
            return color
        }
    }
    return 0;
}
function isXieFang(i, j) {
    var ns = findNeighbors(i, j) // 4 个中心点
    for (let n of ns) {
        var nn = findNeighbors(n.x, n.y)
        if (nn.length === 4) {
            var c = isAllColorSame(nn)
            if (c !== 0)
                return c
        }
    }
    return 0
}
function countStones() {
    var n = [0, 0, 0]
    for (var i = 0; i < boardSize * boardSize; i++) {
        n[stones[i]]++
    }
    return n
}
function countFang() {
    var n = [0, 0, 0]
    countZhiFang(n, true);
    countXieFang(n, true);
    countLong(n)
    return n
}

function countZhiFang(n, isNeibor = false) {
    var count = 0;
    for (var i = 0; i < boardSize - 1; i++) {
        for (var j = 0; j < boardSize - 1; j++) {
            // 对于每个棋子，往右下方数方
            // console.log("will count ", i, j, i + 1, j + 1)
            for (var k = 1; i + k < boardSize && j + k < boardSize; k++) {
                var positions = [
                    { x: i, y: j },
                    { x: i + k, y: j + k },
                    { x: i + k, y: j },
                    { x: i, y: j + k }]
                var color = isAllColorSame(positions)
                if (color !== 0) {
                    // console.log("is", color, i, j, k)
                    n[color]++;
                }
                if (isNeibor) break;
            }
        }
    }
    return count
}
function countXieFang(n, isNeibor = false) {
    for (var i = 1; i < boardSize - 1; i++) {
        for (var j = 1; j < boardSize - 1; j++) {
            // 对于每个棋子，从中心往外数方
            for (var k = 1; i - k >= 0 && i + k < boardSize && j - k >= 0 && j + k < boardSize; k++) {
                var positions = [
                    { x: i - k, y: j },
                    { x: i + k, y: j },
                    { x: i, y: j - k },
                    { x: i, y: j + k }]
                var color = isAllColorSame(positions)
                if (color !== 0) {
                    // console.log("xie", color, i, j, k)
                    n[color]++;
                }
                if (isNeibor) break;
            }
        }
    }
}
function countLong(n) {
    for (var i = 0; i < boardSize; i++) {
        var positions = []
        for (var j = 0; j < boardSize; j++) {
            positions.push({ x: i, y: j })
        }
        // console.log(positions)
        var color = isAllColorSame(positions)
        if (color !== 0) {
            // console.log("i", color, i)
            n[color]++;
        }
    }
    for (var j = 0; j < boardSize; j++) {
        var positions = []
        for (var i = 0; i < boardSize; i++) {
            positions.push({ x: i, y: j })
        }
        var color = isAllColorSame(positions)
        if (color !== 0) {
            console.log("j", color, j)
            n[color]++;
        }
    }
}
function canMove(color) {
    for (var i = 0; i < boardSize; i++) {
        for (var j = 0; j < boardSize; j++) {
            if (sget(i, j) === color) {
                var ns = findNeighbors(i, j)
                if (ns.filter(p => sget(p.x, p.y) === 0).length > 0) {
                    return true
                }
            }
        }
    }
    return false
}
function countNotFang() {
    var cnt = 0
    for (var i = 0; i < boardSize; i++) {
        for (var j = 0; j < boardSize; j++) {
            if (sget(i, j) > 0 && isFang(i, j) === 0) {
                cnt++
            }
        }
    }
    return cnt;
}
function calculateTizi() {
    var n = countFang()
    console.log("fang,long", n)
    if (n[BLACK] === 0 && n[WHITE] === 0) {
        turn = WHITE;
        nums = [0, 1, 1]
    } else if (n[BLACK] === 0 || n[WHITE] === 0) {
        turn = WHITE;
        nums = [0, n[BLACK] + 1, n[WHITE] + 1]
    } else {
        turn = n[BLACK] > n[WHITE] ? BLACK : WHITE;
        nums = [0, 1, 1]
        nums[turn] = n[turn] - n[flipColor(turn)] + 1
    }
    console.log("to tizi", nums)
}
var tizi = function (x, y, color) {
    // 首先检测周围的不同色棋子是否可以提
    // 如不可，则继续检测自身
    var gs = findGroupsColor(x, y, 3 - color)
    var indexs = [];
    for (let i of gs) {
        var qis = stoneGroups[i].qis;
        // console.log(qis.values().length)
        if (qis.size == 0) {
            indexs.push(i)
            removeStonesOnBoard(stoneGroups[i].stones.values())
        }
    }
    if (indexs.length > 0) {
        stoneGroups = sgRemoveItems(indexs)
        sgUpdateAllQi()
    } else {
        // 自杀
        var gs = findGroupsColor(x, y, color)
        if (gs.length > 0) {
            var i = gs[0];
            if (stoneGroups[i].qis.size == 0) {
                removeStonesOnBoard(stoneGroups[i].stones.values())
                // removeStonesOnBoard([{ x: x, y: y }])
                stoneGroups = sgRemoveItems([i])
                sgUpdateAllQi()
                return true;
            }
        }
    }
    return false;
}
var isAllColor = function (lst, color) {
    for (let p of lst) {
        if (sget(p.x, p.y) != color) {
            return false;
        }
    }
    return true;
}
// 是否同样颜色，如是，返回颜色
var isAllColorSame = function (lst) {
    var color = sget(lst[0].x, lst[0].y);
    for (let p of lst) {
        if (sget(p.x, p.y) != color) {
            return 0;
        }
    }
    return color;
}

// ==== 以下是画图函数 ====

var drawBackground = function () {
    ctx.save();
    ctx.fillStyle = "white"
    ctx.fillRect(0, 0, 800, 600)
    ctx.restore();
}
var drawLine = function (x1, y1, x2, y2) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.closePath();
    ctx.stroke();
}
// drawLine(10, 10, 100, 100)
var drawLines = function (n) {
    var lastLine = (n - 1) * gridSize;
    for (var i = 0; i < n; i++) {
        var x = i * gridSize;
        drawLine(x, 0, x, lastLine)
    }
    for (var i = 0; i < n; i++) {
        var y = i * gridSize;
        drawLine(0, y, lastLine, y)
    }
}
// drawLines(19);
var drawStar = function (x, y) {
    ctx.beginPath();

    var radius = 4; // 圆弧半径
    var startAngle = 0; // 开始点
    var endAngle = 2 * Math.PI; // 结束点
    var anticlockwise = false; // 顺时针或逆时针

    ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

    ctx.fill();
}
// drawStar(10, 10);
var drawStars = function () {
    var n = 3;
    for (var i = 0; i < n; i++) {
        var x = 3 * gridSize + i * (6 * gridSize);
        for (var j = 0; j < n; j++) {
            var y = 3 * gridSize + j * (6 * gridSize);
            drawStar(x, y)
        }
    }
}
var drawPanel = function (n) {
    ctx.translate(beginPoint.x, beginPoint.y)
    drawLines(n)
    // drawStars()
}
// drawPanel(boardSize)

var drawCursor = function (x, y) {
    ctx.save()
    var x = x * gridSize;
    var y = y * gridSize
    ctx.beginPath();

    var radius = 6; // 圆弧半径
    var startAngle = 0; // 开始点
    var endAngle = 2 * Math.PI; // 结束点
    var anticlockwise = false; // 顺时针或逆时针

    ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

    ctx.strokeStyle = 'red'
    ctx.stroke();
    ctx.restore();
}
// drawCursor(10, 10)

var drawStone = function (x, y, color) {
    ctx.save()
    var x = x * gridSize;
    var y = y * gridSize
    ctx.beginPath();

    var radius = stoneSize; // 圆弧半径
    var startAngle = 0; // 开始点
    var endAngle = 2 * Math.PI; // 结束点
    var anticlockwise = false; // 顺时针或逆时针

    ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

    ctx.strokeStyle = 'black'
    ctx.stroke();
    ctx.fillStyle = color == 1 ? 'black' : 'white'
    ctx.fill();

    ctx.restore();
}
var drawStoneAbs = function (x, y, color) {
    ctx.save()
    ctx.beginPath();

    var radius = stoneSize; // 圆弧半径
    var startAngle = 0; // 开始点
    var endAngle = 2 * Math.PI; // 结束点
    var anticlockwise = false; // 顺时针或逆时针

    ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

    ctx.strokeStyle = 'black'
    ctx.stroke();
    ctx.fillStyle = color == 1 ? 'black' : 'white'
    ctx.fill();

    ctx.restore();
}
var drawStoneGlow = function (x, y) {
    ctx.save()
    var x = x * gridSize;
    var y = y * gridSize
    ctx.beginPath();

    var radius = stoneSize + 3; // 圆弧半径
    var startAngle = 0; // 开始点
    var endAngle = 2 * Math.PI; // 结束点
    var anticlockwise = false; // 顺时针或逆时针

    ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

    ctx.strokeStyle = 'black'
    ctx.stroke();

    ctx.restore();
}
function drawStageText(text) {
    ctx.save()

    ctx.font = "32px serif";
    ctx.fillText(text, 0, -25);

    ctx.restore();
}

_C.addEventListener("mousemove", function (event) {
    // console.log(event.x-beginPoint.x,event.y-beginPoint.y)
    var x = event.x - beginPoint.x;
    var y = event.y - beginPoint.y
    var i = Math.round(x / gridSize);
    var j = Math.round(y / gridSize);
    cursorPos.x = i; cursorPos.y = j;
    // console.log(cursorPos);
    // console.log(findNeighbors(i,j))
})
var _Tpu = document.getElementById("T")
_C.addEventListener("click", function (event) {
    // console.log("i,j", cursorPos.x, cursorPos.y)
    if (cursorPos.x < boardSize && cursorPos.y < boardSize) {
        // 1、布局下子
        if (stage === 1) {
            if (sget(cursorPos.x, cursorPos.y) == 0) {
                oldsgs = stoneGroups

                console.log("doit", cursorPos.x, cursorPos.y, turn)

                makeMove(cursorPos, turn)
                if (first === 0) {
                    first = isFang(cursorPos.x, cursorPos.y)
                    if (first !== 0) {
                        console.log("第一个", first)
                    }
                }

                nums[turn]--
                console.log(nums)

                var pu = "" + cursorPos.x + "," + cursorPos.y + " " + turn
                console.log(pu)
                _Tpu.value += pu + "\r\n"

                turn = 3 - turn;

                if (boardFull()) {
                    console.log("满了")
                    calculateTizi()
                    stage = 2
                    console.log("提子阶段")
                }
            }
        } else if (stage === 2) { // 2、开局提子 
            if (sget(cursorPos.x, cursorPos.y) === flipColor(turn) && (nums[BLACK] > 0 || nums[WHITE] > 0)) {
                console.log("ti", cursorPos.x, cursorPos.y, turn)

                sset(cursorPos.x, cursorPos.y, 0)

                nums[turn]--
                console.log(nums)

                turn = flipColor(turn);
                if (nums[turn] <= 0) {
                    turn = flipColor(turn);
                }

                if (nums[BLACK] <= 0 && nums[WHITE] <= 0) {
                    console.log("提子结束")
                    stage = 3
                    if (first !== 0) {
                        turn = first
                    } else {
                        turn = WHITE
                    }
                }
            }
        } else if (stage === 3) { // 3、行棋吃子
            // 判断胜利
            var n = countStones();
            if (n[BLACK] <= 3) {
                console.log("白方胜利")
                stage = 5;
            } else if (n[WHITE] <= 3) {
                console.log("黑方胜利")
                stage = 5;
            } else if (!canMove(turn)) {
                console.log("胜利！" + flipColor(turn))
                stage = 5;
            } else if (moveCount > 20) {
                console.log("和棋")
                stage = 5;
            }

            // 走子
            if (sget(cursorPos.x, cursorPos.y) === turn) {
                curStone = { x: cursorPos.x, y: cursorPos.y }
            } else if (sget(cursorPos.x, cursorPos.y) === 0 && curStone != null) {
                if (findNeighbors(cursorPos.x, cursorPos.y).filter(p => p.x === curStone.x && p.y == curStone.y).length > 0) {
                    // 移动
                    sset(curStone.x, curStone.y, 0)
                    sset(cursorPos.x, cursorPos.y, turn)
                    curStone = null
                    moveCount++
                    console.log("步数", moveCount)
                    if (isFangOrLong(cursorPos.x, cursorPos.y) !== 0) {
                        stage = 4
                        console.log("提1个子")
                    } else {
                        if (moveCount >= 20) {
                            console.log("和棋")
                            stage = 5;
                        }

                        turn = flipColor(turn)
                    }
                }
            }
        } else if (stage === 4) { // 提一个子
            if (sget(cursorPos.x, cursorPos.y) === flipColor(turn)) {
                var n = countStones()
                if (countNotFang() > 0) {
                    if (isFang(cursorPos.x, cursorPos.y)) {
                        console.log("不可以提哦（是方哦）")
                        return
                    }
                }
                sset(cursorPos.x, cursorPos.y, 0)
                if (n[BLACK] <= 3) {
                    console.log("白方胜利")
                    stage = 5;
                } else if (n[WHITE] <= 3) {
                    console.log("黑方胜利")
                    stage = 5;
                }
                if (!canMove(flipColor(turn))) {
                    console.log("胜利，困毙", turn)
                    stage = 5
                } else {
                    stage = 3
                    turn = flipColor(turn)
                    moveCount = 0
                }
            }
        }
    }
})
document.getElementsByTagName("body")[0].addEventListener("keyup", function (event) {
    // console.log(event)
    if (event.target == this && event.key == 'f') {
        turn = 3 - turn;
    }
})
_Tpu.addEventListener("change", function (event) {
    var v = _Tpu.value
    if (v.length > 0) {
        if (v[v - 1] != '\n') _Tpu.value += '\n';
    }
})
var RePlay = document.getElementById("RePlay");
var replay = function (pu) {
    boardClear();
    var z = pu.split(/\n|\r|\r\n/)
    var i = 0;
    for (let ins of z) {
        i++;
        ins = ins.trim()
        if (ins.length > 0) {
            var a = ins.split(" ")
            var color = parseInt(a[1])
            var aa = a[0].split(",")
            var x = parseInt(aa[0]), y = parseInt(aa[1])
            if (sget(x, y) !== 0) {
                alert("第" + i + "行 重复落子 " + ins)
                break;
            }
            makeMove({ x: x, y: y }, color)

            turn = flipColor(color)
        }
    }
}
RePlay.addEventListener("click", function (event) {
    if (confirm("确定要重现棋谱？棋盘将会清空")) {
        replay(_Tpu.value)
    }
})

function init() {
    boardClear();
    // makeFullBoard()
}
function step(timestamp) {
    ctx.save();
    drawBackground();
    drawPanel(boardSize)

    // 画棋子
    for (var i = 0; i < boardSize; i++) {
        for (var j = 0; j < boardSize; j++) {
            if (sget(i, j)) {
                drawStone(i, j, sget(i, j))
            }
        }
    }

    if (stage === 1) {
        drawStageText("布局")
    } else if (stage === 2) {
        drawStageText("提子")
    } else if (stage === 3) {
        drawStageText("行棋")
        if (curStone !== null) {
            drawStoneGlow(curStone.x, curStone.y)
        }
    } else if (stage === 4) {
        drawStageText("提子")
    }

    if (cursorPos.x >= 0 && cursorPos.y >= 0 && cursorPos.x < boardSize && cursorPos.y < boardSize) {
        // console.log("i,j", i, j)
        drawCursor(cursorPos.x, cursorPos.y)
    }

    // 当前棋子颜色
    drawStoneAbs((boardSize + 1) * gridSize, 1 * gridSize, turn);

    ctx.restore()

    window.requestAnimationFrame(step);
}
init();
window.requestAnimationFrame(step);
